package com.jandar.ds.service;

import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jandar.ds.mapper.DbInfoMapper;
import com.jandar.ds.pojo.DbInfo;
import com.jandar.ds.pojo.DbInfoExample;
import com.jandar.ds.pojo.DbInfoPower;
import com.jandar.ds.pojo.ListQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author xiongxx
 * @date 2022/4/20 10:39
 * @description
 */
@Service
public class DbInfoService {
    @Autowired
    private DbInfoMapper dbInfoMapper;

    @Autowired
    private DbInfoPowerService dbInfoPowerService;

    public static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3Iut6kzu58Acbt4A4U7o1Y1mXNhGnUir3lkHFT2EJa+dvSYNTPWMeBlCxTgRHvqkAzgVtIX+cwfQPDIYODQi/EruICuUQV1k9W9TooDY09w5if7UYDQ2xVyxCUW46sVM0QlwhAsOm21TtPTaQsm1GEVQby3De0Vb12iR9fU7hJwIDAQAB";
    public static final String privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALci63qTO7nwBxu3gDhTujVjWZc2EadSKveWQcVPYQlr529Jg1M9Yx4GULFOBEe+qQDOBW0hf5zB9A8Mhg4NCL8Su4gK5RBXWT1b1OigNjT3DmJ/tRgNDbFXLEJRbjqxUzRCXCECw6bbVO09NpCybUYRVBvLcN7RVvXaJH19TuEnAgMBAAECgYEAkLrvIErVa8fOxk/J7Dn3MhQXDJJ1dydPv6Umy1lFVd3J5EBToegkuejBwq3mYhDCnVk0Hp/Xqzn4uB/snZQdcRWJTt/04WThsGiZpd3YG427LCbq/54uj+WZN/MXGJh5JGLTi9ISUy4A0qxuqhbdWJZD3I5aASRf9eGMkvn0cykCQQDa+N9+YzDWrd9UIMd4w174V5oiD6uXbNxSXiPmBTkYOU2mwc5SGKKwG/MoX0oKZiH4HAC5ZP22LDlVBKwnkqtbAkEA1hq/AKIxJe9UJy3F9nsZJeRAa312vA08dbyRwJLWm616LwpggIZf2a/YxBgtPPSxQrELwHkvlJC9HZYQxwfnJQI/cAzqUMJxO2m93k7nw+Q1tN8fAE8Ef3g1RfDmbc4+aSbplWuXKGty1Kt4wjAAs1GQEGZD+Jq1OYNn0xmQ/q8PAkAdwv4GAoW+djRGdfBswNPQFph12KzmmxhqbVn9YOwAG+8+Fr0vYH52biE9sPao4IK7eIzfpnjct/nx4OhYIlsZAkBJ1SW6ruzeX8sKFR1h/MbzLYQnJPWVZcN4vOveVLJ8ghiZffbZvk2aDnQ+I+kVTq4AVsNfuGUPq/oqtUyy2oSH";

    private static Map<String, DbInfo> dbInfoCache = new HashMap<>();


    public int insert(DbInfo dbInfo, Integer userId) {
        String regEx="((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(dbInfo.getUrl());
        if (m.find()) {
            String ip = m.group();
            DbInfoExample example = new DbInfoExample();
            DbInfoExample.Criteria criteria = example.createCriteria();
            criteria.andCodeEqualTo(ip + "_" + dbInfo.getDb());
            List<DbInfo> list = dbInfoMapper.selectByExample(example);
            if (!list.isEmpty()) {
                return 0;
            }
            dbInfo.setCode(ip + "_" + dbInfo.getDb());
        }
        encrypt(dbInfo);
        int insert = dbInfoMapper.insert(dbInfo);
        Integer id = dbInfo.getId();
        DbInfoPower power = new DbInfoPower();
        power.setDbInfoId(id);
        power.setUserId(userId);
        dbInfoPowerService.save(Collections.singletonList(power));
        return insert;
    }

    public void update(DbInfo dbInfo) {
        encrypt(dbInfo);
        dbInfoMapper.updateByPrimaryKeySelective(dbInfo);
    }

    public PageInfo<DbInfo> list(ListQuery<DbInfo> dbInfoListQuery, Integer userId, Integer roleId, Integer deptId) {
        PageHelper.startPage(dbInfoListQuery.getPage(), dbInfoListQuery.getRows());
        DbInfo dbInfo = dbInfoListQuery.getEntity();
        DbInfoExample example = new DbInfoExample();
        DbInfoExample.Criteria criteria = example.createCriteria();
        final List<Integer> integers = dbInfoPowerService.listByPower(userId, roleId, deptId);
        if (integers.isEmpty()) {
            return PageInfo.of(Collections.emptyList());
        }
        criteria.andIdIn(integers);
        if (dbInfo != null && dbInfo.getDb() != null) {
            criteria.andDbLike(dbInfo.getDb());
        }
        List<DbInfo> dbInfos = dbInfoMapper.selectByExample(example);
        for (DbInfo d : dbInfos) {
            decrypt(d);
        }
        return PageInfo.of(dbInfos);
    }

    public DbInfo get(Integer id) {
        DbInfo dbInfo = dbInfoMapper.selectByPrimaryKey(id);
        decrypt(dbInfo);
        return dbInfo;
    }

    public DbInfo get(String code) {
        if (dbInfoCache.containsKey(code)) {
            return dbInfoCache.get(code);
        }
        DbInfoExample example = new DbInfoExample();
        DbInfoExample.Criteria criteria = example.createCriteria();
        criteria.andCodeEqualTo(code);
        List<DbInfo> list = dbInfoMapper.selectByExample(example);
        if (!list.isEmpty()) {
            decrypt(list.get(0));
            dbInfoCache.put(code, list.get(0));
            return list.get(0);
        }
        return null;
    }

    public void delete(Integer id) {
        dbInfoMapper.deleteByPrimaryKey(id);
        dbInfoPowerService.deleteByDbId(id);
    }

    public List<DbInfo> getByName(String dbName) {
        DbInfoExample example = new DbInfoExample();
        DbInfoExample.Criteria criteria = example.createCriteria();
        criteria.andDbEqualTo(dbName);
        List<DbInfo> dbInfos = dbInfoMapper.selectByExample(example);
        for (DbInfo dbInfo : dbInfos) {
            decrypt(dbInfo);
        }
        return dbInfos;
    }


    /**
     * 加密 username 和 password
     * @param dbInfo
     */
    public static void encrypt(DbInfo dbInfo) {
        RSA rsa = new RSA(privateKey, publicKey);
        if (dbInfo.getUsername() != null) {
            dbInfo.setUsername(rsa.encryptBase64(dbInfo.getUsername(), KeyType.PublicKey));
        }
        if (dbInfo.getPassword() != null) {
            dbInfo.setPassword(rsa.encryptBase64(dbInfo.getPassword(), KeyType.PublicKey));
        }

    }

    /**
     * 解密 username 和 password
     * @param dbInfo
     */
    public static void decrypt(DbInfo dbInfo) {
        RSA rsa = new RSA(privateKey, publicKey);
        if (dbInfo.getUsername() != null) {
            dbInfo.setUsername(rsa.decryptStr(dbInfo.getUsername(), KeyType.PrivateKey));
        }
        if (dbInfo.getPassword() != null) {
            dbInfo.setPassword(rsa.decryptStr(dbInfo.getPassword(), KeyType.PrivateKey));
        }

    }

    public DbInfo selectByDbCode(String code) {
        DbInfo dbInfo = dbInfoMapper.selectByDbCode(code);
        decrypt(dbInfo);
        return dbInfo;
    }
}
